package tool.json

import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.rememberTextFieldVerticalScrollState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.*
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import components.SplitPanel
import kotlinx.coroutines.runBlocking
import org.jetbrains.compose.resources.getString
import tool.Tool
import tool.ToolEvent
import top.mcwebsite.devtoolbox.devtoolbox.generated.resources.Res
import top.mcwebsite.devtoolbox.devtoolbox.generated.resources.json_to_kotlin
import kotlin.math.roundToInt

object JsonToKotlinTool : Tool {

    private val _name: String by lazy {
        runBlocking {
            getString(Res.string.json_to_kotlin)
        }
    }

    override fun getName(): String {
        return _name
    }

    @Composable
    override fun Render(onEvent: (ToolEvent) -> Unit) {
        val state = remember { JsonToKotlinState() }
        Column {
            Row(
                verticalAlignment = Alignment.CenterVertically
            ) {
                IconButton(onClick = { onEvent(ToolEvent.BackEvent) }) {
                    Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
                }
                Text(text = getName(), style = MaterialTheme.typography.headlineSmall)
            }
            SplitPanel(
                leftMinSize = 300.dp,
                rightMinSize = 300.dp,
                modifier = Modifier
                    .background(MaterialTheme.colorScheme.surface)
                    .border(
                        width = 1.dp,
                        MaterialTheme.colorScheme.outline.copy(alpha = 0.5f),
                        shape = MaterialTheme.shapes.large
                    ),
                left = {
                    CodeEditorView(
                        jsonToKotlinState = state,
                        modifier = Modifier.padding(16.dp)
                    )
                },
                right = {
                    KotlinCodeShow(state = state)
                },
                splitter = {
                    Box(
                        modifier = Modifier.fillMaxHeight().width(2.dp)
                            .background(SolidColor(MaterialTheme.colorScheme.tertiary))
                    )
                })
        }
    }
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun CodeEditorView(
    jsonToKotlinState: JsonToKotlinState,
    modifier: Modifier = Modifier
) {
    val textFieldValue = remember { mutableStateOf(TextFieldValue(AnnotatedString(""))) }
    var textLayout: TextLayoutResult? by remember { mutableStateOf(null) }
    val textFieldScrollState = rememberTextFieldVerticalScrollState()
    val lineNumScrollState = rememberScrollState()
    LaunchedEffect(textFieldScrollState.offset) {
        lineNumScrollState.scrollTo(textFieldScrollState.offset.roundToInt())
    }
    Row(modifier = modifier) {
        Column(
            modifier = Modifier.verticalScroll(lineNumScrollState),
            horizontalAlignment = Alignment.End
        ) {
            val lineCount = textLayout?.lineCount ?: 0
            repeat(lineCount) {
                Text(
                    text = (it + 1).toString(),
                    style = LocalTextStyle.current.copy(color = LocalTextStyle.current.color.copy(alpha = 0.5f)),
                    textAlign = TextAlign.End
                )
            }
        }
        Box(
            modifier = Modifier
                .fillMaxHeight()
                .padding(horizontal = 8.dp)
                .width(1.dp)
                .background(Color.Gray.copy(alpha = 0.5f))
        )
        BasicTextField(
            value = textFieldValue.value,
            onValueChange = { v ->
                textFieldValue.value = v
                jsonToKotlinState.convert(textFieldValue.value.text)
            },
            onTextLayout = {
                textLayout = it
            },
            textStyle = LocalTextStyle.current,
            modifier = Modifier.fillMaxSize().horizontalScroll(rememberScrollState()),
            decorationBox = {
                if (textFieldValue.value.text.isEmpty()) {
                    Text("请输入 json", color = LocalTextStyle.current.color.copy(alpha = 0.5f))
                }
                it()
            },
            scrollState = textFieldScrollState,
        )
    }
}

@Composable
fun KotlinCodeShow(state: JsonToKotlinState) {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(12.dp)
            .verticalScroll(rememberScrollState())
    ) {
        var textLayout: TextLayoutResult? by remember { mutableStateOf(null) }
        Row(
            modifier = Modifier.height(IntrinsicSize.Max)
        ) {
            Column(
                horizontalAlignment = Alignment.End
            ) {
                val lineCount = textLayout?.lineCount ?: 0
                repeat(lineCount) {
                    Text(
                        text = (it + 1).toString(),
                        style = LocalTextStyle.current.copy(color = LocalTextStyle.current.color.copy(alpha = 0.5f)),
                        textAlign = TextAlign.End
                    )
                }
            }
            Box(
                modifier = Modifier
                    .fillMaxHeight()
                    .padding(horizontal = 8.dp)
                    .width(1.dp)
                    .background(Color.Gray.copy(alpha = 0.5f))
            )
            SelectionContainer {
                Text(
                    state.kotlinOutput.value,
                    style = LocalTextStyle.current,
                    onTextLayout = {
                        textLayout = it
                    }
                )
            }
        }
    }
}